#ifndef __WIZ_ALGEBRA_MATRIX44_COLMAJOR_METHOD_HPP__SHANHAOBO_19800429__
#define __WIZ_ALGEBRA_MATRIX44_COLMAJOR_METHOD_HPP__SHANHAOBO_19800429__

#include "../../Utils/WizAlgebraUtils.hpp"

#include "../Matrix33/WizAlgebraMatrix33ColMajorMethod.hpp"
#include "../Vector3/WizAlgebraVector3.hpp"
#include "../Vector4/WizAlgebraVector4.hpp"

namespace Wiz
{
    namespace Matrix44
    {
        namespace ColMajor
        {
            namespace Method
            {
                template<class MatrixT>
                struct Type
                {
                    ////////////////////////////////////////////////////////////////
                    typedef MatrixT                                             tMatrix;
                    typedef typename tMatrix::tElement                          tElement;
                    typedef Type<tMatrix>                                       tThis;
                    typedef ::Wiz::Matrix33::ColMajor::Method::Type<tMatrix>    tMatrix33;
                    typedef ::Wiz::Vector3::Type<tElement>                      tVector3;
                    typedef ::Wiz::Vector4::Type<tElement>                      tVector4;
                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static tMatrix& FromElement(tMatrix& OutMat, const tElement& InEle);
                    ////////////////////////////////////////////////////////////////
                    template<class Matrix22T>
                    WIZ_INLINE static tMatrix& FromMatrix22(tMatrix& OutMat, const Matrix22T& InMat);
                    template<class Matrix22T>
                    WIZ_INLINE static Matrix22T& ToMatrix22(Matrix22T& OutMat, const tMatrix& InMat);

                    template<class Matrix33T>
                    WIZ_INLINE static tMatrix& FromMatrix33(tMatrix& OutMat, const Matrix33T& InMat);
                    template<class Matrix33T>
                    WIZ_INLINE static Matrix33T& ToMatrix33(Matrix33T& OutMat, const tMatrix& InMat);

                    template<class Matrix43T>
                    WIZ_INLINE static tMatrix& FromMatrix43(tMatrix& OutMat, const Matrix43T& InMat);
                    template<class Matrix43T>
                    WIZ_INLINE static Matrix43T& ToMatrix43(Matrix43T& OutMat, const tMatrix& InMat);

                    template<class Matrix44T>
                    WIZ_INLINE static tMatrix& FromMatrix44(tMatrix& OutMat, const Matrix44T& InMat);
                    template<class Matrix44T>
                    WIZ_INLINE static Matrix44T& ToMatrix44(Matrix44T& OutMat, const tMatrix& InMat);
                    ////////////////////////////////////////////////////////////////

                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static tMatrix& Add(tMatrix& OutMat, const tMatrix& InMat1, const tMatrix& InMat2);
                    WIZ_INLINE static tMatrix& AddAssign(tMatrix& InOutMat, const tMatrix& InMat)
                    {
                        return tThis::Add(InOutMat, InOutMat, InMat);
                    }

                    WIZ_INLINE static tMatrix& Subtract(tMatrix& OutMat, const tMatrix& InMat1, const tMatrix& InMat2);
                    WIZ_INLINE static tMatrix& SubtractAssign(tMatrix& InOutMat, const tMatrix& InMat)
                    {
                        return tThis::Subtract(InOutMat, InOutMat, InMat);
                    }

                    WIZ_INLINE static tMatrix& Multiply(tMatrix& OutMat, const tMatrix& InMat1, const tElement& InEle);
                    WIZ_INLINE static tMatrix& MultiplyAssign(tMatrix& InOutMat, const tElement& InEle)
                    {
                        return tThis::Multiply(InOutMat, InOutMat, InEle);
                    }

                    WIZ_INLINE static tMatrix& Multiply(tMatrix& OutMat, const tMatrix& InMat1, const tMatrix& InMat2);
                    WIZ_INLINE static tMatrix& MultiplyAssign(tMatrix& InOutMat, const tMatrix& InMat)
                    {
                        return tThis::Multiply(InOutMat, InOutMat, InMat);
                    }

                    WIZ_INLINE static tVector3& Multiply(tVector3& OutVec3, const tVector3& InVec3, const tMatrix& InMat);
                    WIZ_INLINE static tVector3& MultiplyAssign(tVector3& InOutVec3, const tMatrix& InMat)
                    {
                        return tThis::Multiply(InOutVec3, InOutVec3, InMat);
                    }

                    WIZ_INLINE static tVector4& Multiply(tVector4& OutVec4, const tVector4& InVec4, const tMatrix& InMat);
                    WIZ_INLINE static tVector4& MultiplyAssign(tVector4& InOutVec4, const tMatrix& InMat)
                    {
                        return tThis::Multiply(InOutVec4, InOutVec4, InMat);
                    }
                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static ::Wiz::Bool::Type IsEqual(const tMatrix& InMat1, const tMatrix& InMat2);
                    WIZ_INLINE static ::Wiz::Bool::Type NotEqual(const tMatrix& InMat1, const tMatrix& InMat2)
                    {
                        return  IsEqual(InMat1, InMat2) == ::Wiz::Bool::False;
                    }
                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static tElement Determinant
                        (
                        const tElement& E00, const tElement& E10, const tElement& E20, const tElement& E30,
                        const tElement& E01, const tElement& E11, const tElement& E21, const tElement& E31,
                        const tElement& E02, const tElement& E12, const tElement& E22, const tElement& E32,
                        const tElement& E03, const tElement& E13, const tElement& E23, const tElement& E33
                        );
                    WIZ_INLINE static tElement Determinant(const tMatrix& InMat)
                    {
                        return Determinant
                            (
                            InMat.e00, InMat.e10, InMat.e20, InMat.e30,
                            InMat.e01, InMat.e11, InMat.e21, InMat.e31,
                            InMat.e02, InMat.e12, InMat.e22, InMat.e32,
                            InMat.e03, InMat.e13, InMat.e23, InMat.e33
                            );
                    }
                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static ::Wiz::Bool::Type Invert(tMatrix& OutMat, const tMatrix& InMat);
                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static tMatrix& Transpose(tMatrix& OutMat, const tMatrix& InMat);
                    WIZ_INLINE static tMatrix& Transpose(tMatrix& InOutMat);
                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static tMatrix& Identity(tMatrix& InOutMat);
                    WIZ_INLINE static tMatrix& Zero(tMatrix& InOutMat);
                    ////////////////////////////////////////////////////////////////

                    ////////////////////////////////////////////////////////////////
                    WIZ_INLINE static tMatrix& Negative(tMatrix& OutMat, const tMatrix& InMat);
                    ////////////////////////////////////////////////////////////////
                }; /// end of struct Type
            } /// end of namespace Method
        } /// end of namespace ColMajor
    } /// end of namespace Matrix44
} /// end of namespace Wiz

#include "./WizAlgebraMatrix44ColMajorMethod.inl"

#endif /*__WIZ_ALGEBRA_MATRIX44_COLMAJOR_METHOD_HPP__SHANHAOBO_19800429__*/
